
package analiseSintatica.Regras.Tipos;

import AnaliseLexicaFinal.EstruturaDeDados.LinkToken;
import analiseSemantica.ErroSemantico;
import analiseSemantica.Tipos.TipoSemantico;
import analiseSemantica.Tipos.TiposSemanticos;
import analiseSemantica.estruturadedados.Escopo;
import analiseSemantica.estruturadedados.Identificador;
import analiseSemantica.estruturadedados.Struct;
import analiseSintatica.AnalisadorSintatico;
import analiseSintatica.ErroSintaticoException;
import analiseSintatica.Regras.Declaracoes.RegraDeclaracao;
import analiseSintatica.Regras.Regra;

import java.util.LinkedList;

/**
 *
 * @author Edney
 */
public class RegraStruct extends Regra {

    protected static Regra instancia;

    protected String estrutura = "<struct> ::= struct '{' {<declaracao>}+ '}'";

    /**
     * Construtor privado necessario ao singleton
     */
    private RegraStruct() {
    }

    /**
     * Retorna a unica instancia dessa classe.
     * @return
     */
    public static RegraStruct getInstance() {
        if (instancia == null) {
            instancia = new RegraStruct();
        }
        return (RegraStruct) instancia;
    }

    @Override
    public TiposSemanticos analisar(LinkedList<LinkToken> listaTokens) throws ErroSintaticoException {
    	boolean erro = false;
    	reconheceToken(listaTokens, "struct", estrutura);
    	reconheceLexema(listaTokens, "delimitador","{", estrutura);
    	Struct struct = new Struct(null);
    	Escopo escopoanalise = AnalisadorSintatico.escopoatual;
    	AnalisadorSintatico.escopoatual = null;
    	TiposSemanticos tiposemantico = new TiposSemanticos();;
    	do {
    		TiposSemanticos tipos = RegraDeclaracao.getInstance().analisar(listaTokens);//recebe os tipos semanticos resultados de RegraDeclaração
    		if(tipos != null){
	    		while(tipos.size() != 0){//ate acabar os tipos
	    			TipoSemantico id = tipos.removeTipos();//pega o primeiro da lista
	    			Identificador ident = (Identificador)id.getTipo();//??
	    			if(struct.isCampos(ident.getLexema()))//verifica se o campo já existe na struct
	    				AnalisadorSintatico.errosemanticos.add(new ErroSemantico("Campo "+ident.getLexema()+" ja existe na struct", id.getLinha()));
	    			struct.setCampos(ident.getLexema(), ident.getTipo());//se n existir adiciona ele
	    		}
    		}else
    			erro = true;
    		
        }while(listaContem(RegraDeclaracao.getInstance().getPrimeiro(),listaTokens.getFirst()));
    	tiposemantico.addTipos(new TipoSemantico(struct, listaTokens.getFirst().getLinha()));
        reconheceLexema(listaTokens, "delimitador","}", estrutura);
        AnalisadorSintatico.escopoatual = escopoanalise;

        if(erro)
        	return null;
        return tiposemantico;
    }

    @Override
    protected void setPrimeiro() {
        primeiro.add("struct");
    }
}
